package com.zzq.controller;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sun.jersey.api.client.Client;
import com.zzq.Model.Article;
import com.zzq.Model.ArticleRet;
import com.zzq.Model.Comment;
import com.zzq.Model.User;
import com.zzq.mapper.ArticleMapper;
import com.zzq.mapper.CommentMapper;
import com.zzq.mapper.UserMapper;
import com.zzq.utils.*;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Api("文章接口")
@Controller
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    ArticleMapper articleMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    CommentMapper commentMapper;

    private String imgPath = "upload/article/";    //后台图片保存地址

    private String uploadHost = "http://120.76.157.21:20041/";    //项目host路径

    @ApiOperation(value = "发表文章", response = Article.class)
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="query", name = "title", value = "文章标题", dataType = "String"),
            @ApiImplicitParam(paramType="query", name = "body", value = "文章内容", dataType = "String")
    })
    @PostMapping("post.do")
    @ResponseBody
    public IResult post(@RequestHeader("token") String token, HttpServletRequest request) {
        try {
            String title = request.getParameter("title");
            String body = request.getParameter("body");

            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            User user = null;
            user = userMapper.getById(userId);
            if(user == null) {
                return IResult.error("用户不存在");
            }
            if(title == null || body == null || "".equals(title) || "".equals(body)) {
                return IResult.error("发表文章请填写标题和正文！");
            } else if(body.length() > 60000) {
                return IResult.error("评" +
                        "论内容不能超过60000字");
            }

            Article article = new Article();
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            article.setUserId(userId).setTitle(title).setBody(body).setCreateTime(now.format(df)).setUpdateTime(now.format(df));

            articleMapper.add(article);
            return IResult.success("发表成功", article);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("删除指定id文章")
    @ApiImplicitParam(paramType="path", name = "articleId", value = "文章编号", dataType = "Integer")
    @DeleteMapping("{articleId}")
    @ResponseBody
    public IResult deleteById(@RequestHeader("token") String token, @PathVariable("articleId") Integer articleId) {
        try {
            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            Article article = articleMapper.getById(articleId);

            if(article == null) {
                return IResult.error("文章不存在");
            }

            if(article.getUserId() == userId || userMapper.getById(userId).getIsSuperuser() == 1) {
                if(article.getAvatar() != null && !"".equals(article.getAvatar())) {
                    Upload.delete(article.getAvatar());
                }

                articleMapper.deleteById(articleId);
                return IResult.success("删除成功");
            }
            return IResult.error("只有管理员和自己可以删除文章");
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("更新文章")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="path", name = "articleId", value = "文章编号", dataType = "Integer"),
            @ApiImplicitParam(paramType="query", name = "title", value = "标题", dataType = "String"),
            @ApiImplicitParam(paramType="query", name = "body", value = "正文", dataType = "String"),
    })
    @PostMapping("{articleId}")
    @ResponseBody
    public IResult edit(@RequestHeader("token") String token, @PathVariable("articleId") int articleId, HttpServletRequest request) {
        try {
            String title = request.getParameter("title");
            String body = request.getParameter("body");

            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            Article article = articleMapper.getById(articleId);

            if(article == null) {
                return IResult.error("文章不存在");
            }
            if(article.getUserId() == userId || userMapper.getById(userId).getIsSuperuser() == 1) {
                if(title == null || body == null || "".equals(title) || "".equals(body)) {
                    return IResult.error("发表文章请填写标题和正文！");
                }
                LocalDateTime localDateTime = LocalDateTime.now();
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                articleMapper.edit(articleId, title, body, localDateTime.format(df));
                return IResult.success("修改成功");
            }
            return IResult.error("只有管理员和自己可以编辑文章");
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("增加文章浏览量, 并且当前用户的访问量也会增加, 若发生异常, 则一个也不会增加")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="query", name = "articleId", value = "文章序号", dataType = "Integer")
    })
    @PostMapping("addTotalView.do")
    @ResponseBody
    @Transactional(propagation = Propagation.REQUIRED)
    public IResult addToalView(@RequestHeader("token") String token, HttpServletRequest request) {
        int articleId = Integer.parseInt(request.getParameter("articleId"));

        Claims claims = JWTUtil.verifyToken(token);
        int userId = Integer.parseInt((String) claims.get("jti"));
        Article article = null;
        article = articleMapper.getById(articleId);
        if(article == null) {
            return IResult.error("文章不存在");
        }

        articleMapper.addTotalView(articleId);
        userMapper.addReadCount(userId);
        return IResult.success();
    }

    @ApiModelProperty("文章点赞")
    @ApiImplicitParam(paramType="query", name = "articleId", value = "文章序号", dataType = "Integer")
    @PostMapping("addLikes.do")
    @ResponseBody
    public IResult addLikes(HttpServletRequest request) {
        try {
            int articleId = Integer.parseInt(request.getParameter("articleId"));
            if(articleMapper.getById(articleId) == null) {
                return IResult.error("文章不存在");
            }
            articleMapper.addLikes(articleId);
            return IResult.success();
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("取消点赞")
    @ApiImplicitParam(paramType="query", name = "articleId", value = "文章序号", dataType = "Integer")
    @PostMapping("subLikes.do")
    @ResponseBody
    public IResult subLikes(HttpServletRequest request) {
        try {
            int articleId = Integer.parseInt(request.getParameter("articleId"));
            if(articleMapper.getById(articleId) == null) {
                return IResult.error("文章不存在");
            }
            return IResult.success();
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("获取所有文章(先按点赞数逆序排序，再按创建时间逆序排序)")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="query", name = "pageNo", value = "页码", dataType = "Integer"),
            @ApiImplicitParam(paramType="query", name = "pageNum", value = "一页显示的数量", dataType = "Integer"),
            @ApiImplicitParam(paramType="query", name = "page", value = "最大显示的页码个数", dataType = "Integer")
    })
    @GetMapping("")
    @ResponseBody
    public IResult<Article> getAll(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageNum", defaultValue = "5") int pageNum, @RequestParam(value = "page", defaultValue = "5") int page) {
        try {
            int total = articleMapper.getTotal();
            if(pageNo < 1) pageNo = 1;
            if(pageNum <= 0) pageNum = 1;
            else if(pageNum > total) pageNum = total;
            List<Article> articles = articleMapper.getAll((pageNo - 1) * pageNum, pageNum);

            List<ArticleRet> articlesInfo = new ArrayList<>();

            for(Article article : articles) {
                ArticleRet articleRet = new ArticleRet();
                articleRet.setId(article.getId());
                articleRet.setTitle(article.getTitle());
                articleRet.setBody(article.getBody());
                articleRet.setCreateTime(article.getCreateTime());
                articleRet.setUpdateTime(article.getUpdateTime());
                articleRet.setTotalView(article.getTotalView());
                articleRet.setLikes(article.getLikes());
                articleRet.setAvatar(article.getAvatar());
                articleRet.setUser(userMapper.getById(article.getUserId()));
                articleRet.setComments(commentMapper.getByArticleId(article.getId()));
                articlesInfo.add(articleRet);
            }
            IResult iResult = new IResult();
            iResult.setData(articlesInfo);
            iResult.getMap().put("total", total);
            iResult.getMap().put("perPageSize", pageNum);

            int totalPage = total % pageNum == 0 ? total / pageNum : total / pageNum + 1;
            int currentPageSize = 0;
            if(totalPage == pageNo) {
                currentPageSize = total - (pageNo - 1) * pageNum;
            } else {
                currentPageSize = pageNum;
            }
            iResult.getMap().put("totalPage", totalPage);
            iResult.getMap().put("currentPageSize", currentPageSize);
            iResult.getMap().put("pageNo", pageNo);

            List<Integer> pages = new ArrayList<Integer>();
            if(totalPage <= page) {
                for(int i = 1; i <= totalPage; i++) {
                    pages.add(i);
                }
            } else {
                if(pageNo < page) {
                    for(int i = 1; i <= page; i++) {
                        pages.add(i);
                    }
                } else if(pageNo > totalPage - page) {
                    for(int i = totalPage - page + 1; i <= totalPage; i++) {
                        pages.add(i);
                    }
                } else {
                    // pageNo: 6, page: 5, pages: 4 5 6 7 8
                    // pageNo: 6, page: 4, pages: 4 5 6 7
                    // pageNo: 7, page: 5, pages: 5 6 7 8 9
                    // pageNo: 7, page: 4, pages: 5 6 7 8
                    // pageNo: 2, page: 2, total:5
                    for(int i = pageNo - page / 2; i <= pageNo + page / 2; i++) {
                        pages.add(i);
                    }
                    if((pageNo % 2 == 0 && page % 2 == 0 || pageNo % 2 == 1 && page % 2 == 0) && page != 1) {
                        pages.add(pageNo + page / 2);
                    }
                }
            }

            iResult.getMap().put("pages", pages);
            return iResult;
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("获取所有文章(专为unity提供，先按点赞数逆序排序，再按创建时间逆序排序)")
    @GetMapping("unity")
    @ResponseBody
    public IResult<Article> getAllForUnity(@RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageNum", defaultValue = "5") int pageNum, @RequestParam(value = "page", defaultValue = "5") int page) {
        try {
            List<Article> articles = articleMapper.getAllForUnity();

            List<ArticleRet> articlesInfo = new ArrayList<>();

            for(Article article : articles) {
                ArticleRet articleRet = new ArticleRet();
                articleRet.setId(article.getId());
                articleRet.setTitle(article.getTitle());
                articleRet.setBody(article.getBody());
                articleRet.setCreateTime(article.getCreateTime());
                articleRet.setUpdateTime(article.getUpdateTime());
                articleRet.setTotalView(article.getTotalView());
                articleRet.setLikes(article.getLikes());
                articleRet.setAvatar(article.getAvatar());
                articleRet.setUser(userMapper.getById(article.getUserId()));
                articleRet.setComments(commentMapper.getByArticleId(article.getId()));
                articlesInfo.add(articleRet);
            }
            return IResult.success(articlesInfo);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过搜索信息获取文章")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="query", name = "pageNo", value = "页码", dataType = "Integer"),
            @ApiImplicitParam(paramType="query", name = "pageNum", value = "一页显示的数量", dataType = "Integer"),
            @ApiImplicitParam(paramType="query", name = "searchInfo", value = "搜索信息", dataType = "String")
    })
    @GetMapping("search.do")
    @ResponseBody
    public IResult<Article> search(String searchInfo, @RequestParam(value = "pageNo", defaultValue = "1") int pageNo, @RequestParam(value = "pageNum", defaultValue = "5") int pageNum) {
        try {
            Page<Object> objects = PageHelper.startPage(pageNo, pageNum);
            List<Article> articles = articleMapper.getBySearchInfo("%" + searchInfo + "%");
            PageInfo<Article> pageInfo = new PageInfo<Article>(articles);
            return IResult.success(pageInfo);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过文章序号获取文章")
    @ApiImplicitParam(paramType="path", name = "articleId", value = "文章序号", dataType = "Integer")
    @GetMapping("{articleId}")
    @ResponseBody
    public IResult<Article> getById(@PathVariable("articleId") int articleId) {
        try {
            Article a = articleMapper.getById(articleId);

            Map<String, Object> article = new HashMap<>();
            article.put("id", a.getId());
            article.put("title", a.getTitle());
            article.put("body", a.getBody());
            article.put("createTime", a.getCreateTime());
            article.put("updateTime", a.getUpdateTime());
            article.put("totalView", a.getTotalView());
            article.put("likes", a.getLikes());
            article.put("avatar", a.getAvatar());
            article.put("user", userMapper.getById(a.getUserId()));
            article.put("comments", commentMapper.getByArticleId(a.getId()));
            return IResult.success(article);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过点赞排序文章")
    @GetMapping("getOrderByLikes.do")
    @ResponseBody
    public IResult<Article> getOrderByLikes() {
        try {
            List<Article> articles = articleMapper.getOrderByLikes();
            return IResult.success(articles);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过被访问量排序")
    @GetMapping("getOrderByTotalView.do")
    @ResponseBody
    public IResult<Article> getOrderByTotalView() {
        try {
            List<Article> articles = articleMapper.getOrderByTotalView();
            return IResult.success(articles);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过登录用户获取用户的文章")
    @GetMapping("getByUserId.do")
    @ResponseBody
    public IResult<Article> getByUserId(@RequestHeader("token") String token) {
        try {
            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            List<Article> articles = articleMapper.getByUserId(userId);
            return IResult.success(articles);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过登录用户获取用户的文章数量")
    @GetMapping("getCountByUserId.do")
    @ResponseBody
    public IResult getCountByUserId(@RequestHeader("token") String token) {
        try {
            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            int count = articleMapper.getCountByUserId(userId);
            return IResult.success(count);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过登录用户获取用户的文章总被访问量")
    @GetMapping("getTotalViewByUserId.do")
    @ResponseBody
    public IResult getTotalViewByUserId(@RequestHeader("token") String token) {
        try {
            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            int count = articleMapper.getTotalViewByUserId(userId);
            return IResult.success(count);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("通过登录用户获取用户的文章总点赞数")
    @GetMapping("getLikesByUserId.do")
    @ResponseBody
    public IResult getLikesByUserId(@RequestHeader("token") String token) {
        try {
            Claims claims = JWTUtil.verifyToken(token);
            int userId = Integer.parseInt((String) claims.get("jti"));

            int count = articleMapper.getLikesByUserId(userId);
            return IResult.success(count);
        } catch (Exception e) {
            Log.LogWarn(e.toString());
            return IResult.error(e.toString());
        }
    }

    @ApiOperation("修改文章图片")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="path", name = "articleId", value = "文章序号", dataType = "Integer"),
            @ApiImplicitParam(paramType="body", name = "img", value = "图片", dataType = "Picture")
    })
    @PutMapping("updateImg.do/{articleId}")
    @ResponseBody
    public IResult uploadSysHeadImg(HttpServletRequest request, HttpServletResponse response, @PathVariable("articleId") int articleId){
        try {
            IResult iResult = new IResult();

            Article article = articleMapper.getById(articleId);
            if(article.getAvatar() != null || !"".equals(article.getAvatar())) {
                Upload.delete(article.getAvatar());
            }

            MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
            MultipartHttpServletRequest Murequest = resolver.resolveMultipart(request);
            MultipartFile file = Murequest.getFile("img");

            // 实例化一个jersey
            Client client = new Client();

            String fileName = new String();
            String realPath = new String();
            String uploadInfo = Upload.upload(client, file, request, response, uploadHost, imgPath);
            if(!"".equals(uploadInfo)) {    //上传成功
                String[] infoList = uploadInfo.split(";");
                fileName = infoList[0];    //文件名
                // 1为相对路径
                realPath = infoList[2];    //真实完整路径
            } else {    //上传失败
                fileName = "";
                realPath = "";
            }

            iResult.setCode(100);
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            articleMapper.editAvatar(articleId, realPath, LocalDateTime.now().format(df));
            iResult.setMsg("更改成功");
            iResult.getMap().put("fileName", fileName);
            iResult.getMap().put("realPath", realPath);
            return iResult;
        } catch (Exception e) {
            return IResult.error("更改失败");
        }
    }
}
